from PySide6.QtWidgets import (
    QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLineEdit, QPushButton, QFileDialog, QMessageBox,
    QLabel, QComboBox, QGroupBox, QProgressBar, QTextEdit
)
from PySide6.QtGui import QIcon
from PySide6.QtCore import Qt, QThread, Signal
from core.file_utils import FileRenamer
from core.config import LOG_CONFIG
import logging
from datetime import datetime
from gui.styles import load_styles

# 配置日志系统（使用core/config.py中的配置）
logging.basicConfig(**LOG_CONFIG)


class RenameThread(QThread):
    """
    后台重命名线程类
    职责：执行文件重命名操作，避免阻塞主线程
    设计模式：Worker-Thread模式
    """
    progress = Signal(int)  # 进度更新信号（0-100）
    finished = Signal(bool, str)  # 操作完成信号（是否成功，消息）
    log_message = Signal(str)  # 日志消息信号

    def __init__(self, renamer, target_dir, files, prefix):
        """
        初始化线程
        :param renamer: FileRenamer实例 - 核心重命名逻辑
        :param target_dir: str - 目标目录路径
        :param files: list - 待处理文件列表
        :param prefix: str - 文件名前缀
        """
        super().__init__()
        self.renamer = renamer
        self.target_dir = target_dir
        self.files = files
        self.prefix = prefix

    def run(self):
        """线程主执行方法"""
        try:
            total = len(self.files)
            # 使用生成器逐个处理文件并发送信号
            for i, new_name in enumerate(
                    self.renamer.rename_files(self.target_dir, self.files, self.prefix),
                    start=1
            ):
                self.log_message.emit(f"已重命名: {new_name}")
                self.progress.emit(int((i / total) * 100))
            self.finished.emit(True, "重命名完成")
        except Exception as e:
            error_msg = f"操作失败: {str(e)}"
            self.log_message.emit(error_msg)
            self.finished.emit(False, error_msg)


class MainWindow(QMainWindow):
    """
    主窗口类
    职责：管理用户界面和业务逻辑协调
    设计模式：MVC模式中的视图层
    """
    def __init__(self):
        """初始化主窗口组件"""
        super().__init__()

        # 初始化核心组件
        self.renamer = FileRenamer()  # 业务逻辑实例
        self.thread = None  # 后台线程引用

        # 初始化UI组件
        self._init_components()
        self._setup_ui()
        self._connect_signals()

    def _init_components(self):
        """初始化所有UI组件"""
        # 路径相关组件
        self.path_input = QLineEdit()
        self.btn_browse = QPushButton("浏览")

        # 文件类型选择
        self.type_combo = QComboBox()
        self.type_combo.addItems([
            "所有文件", "图片", "视频", "文档",
            "音频", "压缩包", "编程文件", "电子书", "文件夹"
        ])

        # 重命名设置
        self.prefix_input = QLineEdit()
        self.prefix_input.setPlaceholderText("输入前缀，例如: project_")

        # 功能按钮
        self.btn_start = QPushButton("开始重命名")
        self.btn_start.setFixedHeight(16)

        # 状态显示
        self.progress_bar = QProgressBar()
        self.progress_bar.setAlignment(Qt.AlignCenter)
        self.progress_bar.setVisible(False)

        # 日志系统
        self.log_area = QTextEdit()
        self.log_area.setReadOnly(True)

        # 窗口属性
        self.setWindowIcon(QIcon("resources/icons/author_icon.ico"))
        self.setStyleSheet(load_styles())  # 加载样式表
        self.setWindowTitle("文件批量重命名工具")
        self.setMinimumSize(600, 600)  # 最小窗口尺寸

    def _setup_ui(self):
        """构建界面布局"""
        main_widget = QWidget()
        layout = QVBoxLayout(main_widget)

        # 设置全局边距
        layout.setContentsMargins(20, 20, 20, 20)

        # 添加作者信息栏
        layout.addWidget(self._create_author_bar())

        # 功能区域容器
        layout.addWidget(self._create_path_group())
        layout.addWidget(self._create_type_group())
        layout.addWidget(self._create_rename_group())

        # 状态显示区域
        layout.addWidget(self.progress_bar)
        layout.addWidget(self.btn_start)
        layout.addWidget(QLabel("操作日志:"))
        layout.addWidget(self.log_area, 1)  # 日志区域可拉伸

        self.setCentralWidget(main_widget)

    @staticmethod
    def _create_author_bar():
        """创建作者信息栏"""
        author_bar = QWidget()
        layout = QHBoxLayout(author_bar)
        layout.setContentsMargins(0, 0, 0, 10)

        author_label = QLabel("""
            <span style="color: #888888; font-size: 12px;">
                开发者：lzb759（娱乐） | 邮箱：3071137594@qq.com | 当前版本：v0.0.3
                <a href="https://blog.csdn.net/weixin_62565928/article/details/148152555" 
                   style="color: #0078d4;">获取最新版</a>
            </span>
        """)
        author_label.setOpenExternalLinks(True)

        layout.addWidget(author_label)
        layout.addStretch()
        return author_bar

    def _create_path_group(self):
        """创建路径选择组件"""
        group = QGroupBox("目标目录")
        group.setFixedHeight(50)

        layout = QHBoxLayout(group)
        layout.addWidget(self.path_input, 1)  # 输入框占剩余空间
        layout.addWidget(self.btn_browse)  # 按钮固定宽度
        return group

    def _create_type_group(self):
        """创建文件类型选择组件"""
        group = QGroupBox("文件类型")
        group.setFixedHeight(50)

        layout = QHBoxLayout(group)
        layout.addWidget(self.type_combo)
        return group

    def _create_rename_group(self):
        """创建重命名设置组件"""
        group = QGroupBox("命名规则")
        group.setFixedHeight(80)

        layout = QVBoxLayout(group)
        layout.addWidget(QLabel("文件前缀:"))
        layout.addWidget(self.prefix_input)
        return group

    def _connect_signals(self):
        """连接信号与槽"""
        self.btn_browse.clicked.connect(self._on_browse)
        self.btn_start.clicked.connect(self._start_renaming)

    def _on_browse(self):
        """处理目录选择"""
        if dir_path := QFileDialog.getExistingDirectory(self, "选择目录"):
            self.path_input.setText(dir_path)

    def _start_renaming(self):
        """启动重命名流程"""
        # 输入验证
        if not (target_dir := self.path_input.text()):
            QMessageBox.warning(self, "提示", "请先选择目标目录")
            return

        # 获取处理参数
        file_type = self.type_combo.currentIndex()
        prefix = self.prefix_input.text().strip()

        try:
            # 获取并处理文件列表
            files = self._get_sorted_files(target_dir, file_type)
            if not files:
                QMessageBox.information(self, "提示", "当前文件夹无所选文件类型")
                return

            # 启动后台线程
            self._start_rename_thread(target_dir, files, prefix)

        except Exception as e:
            self._handle_error(f"操作失败: {str(e)}")

    def _get_sorted_files(self, target_dir, file_type):
        """获取排序后的文件列表"""
        files = self.renamer.get_file_list(target_dir, file_type)
        return self.renamer.sort_files(files, target_dir, file_type)

    def _start_rename_thread(self, target_dir, files, prefix):
        """启动并配置后台线程"""
        self.progress_bar.reset()  # 重置进度条
        self.progress_bar.setVisible(True)
        self.thread = RenameThread(self.renamer, target_dir, files, prefix)

        # 连接线程信号
        self.thread.log_message.connect(self._update_log)
        self.thread.progress.connect(self._update_progress)
        self.thread.finished.connect(self._on_rename_finished)

        self.thread.start()

    def _update_progress(self, value):
        """更新进度条"""
        self.progress_bar.setValue(value)

    def _on_rename_finished(self, success, msg):
        """处理完成事件"""
        self.progress_bar.setVisible(False)
        QMessageBox.information(self, "完成" if success else "失败", msg)

    def _update_log(self, message):
        """更新日志区域"""
        # 限制日志行数（保留最近500行）
        if self.log_area.document().lineCount() > 500:
            cursor = self.log_area.textCursor()
            cursor.movePosition(cursor.Start)
            cursor.select(cursor.LineUnderCursor)
            cursor.removeSelectedText()
            cursor.deleteChar()
        timestamp = datetime.now().strftime("%H:%M:%S")
        self.log_area.append(f'[{timestamp}] {message}')

    def _handle_error(self, message):
        """统一错误处理"""
        logging.error(message)
        QMessageBox.critical(self, "错误", message)

    def closeEvent(self, event):
        """窗口关闭事件处理"""
        if self.thread and self.thread.isRunning():
            self.thread.quit()  # 请求线程退出
            self.thread.wait(5000)  # 等待5秒
        event.accept()